package com.example.bodycontrolmoduledomain

import android.util.Log
import com.example.bodycontrolmodule.impl.ISkyWindowRepository
import com.example.bodycontrolmodule.impl.SkyWindowRepository
import com.example.datacore.BCMRepositoryImpl
import com.example.datacore.DomainScope
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.combineTransform
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.transform
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import javax.inject.Inject
import javax.inject.Qualifier


data class SkyWinUiState(
    val skyWindTextRes: Int = R.string.sky_win_open_text,
    val windowState:Int = 0,//关闭
    val openEnable: Boolean = true,
    val posValue: Int = 0,
    val posEnable: Boolean = true
)


@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class DomainExceptionHandler


@Module
@InstallIn(SingletonComponent::class)
object DomainScopeProvider {

    @Provides
    @DomainScope
    fun createDomainScope() = CoroutineScope(Dispatchers.Default)
    /*带有异常处理机制的scope
    fun createDomainScope(@DomainExceptionHandler handler: CoroutineExceptionHandler) = CoroutineScope(Dispatchers.Default+handler)
*/
}

/**
 * 打开天窗逻辑case
 * */
class SkyWindowUseCase @Inject constructor(
    @SkyWindowRepository //标识符
    private val windowRepository: ISkyWindowRepository,
    @DomainScope
    private val domainScope: CoroutineScope
) {

    private val TAG = "SkyWindowUseCase"
    private val DEFAULT_STATE = SkyWinUiState()


    private val _mutableUiStateFlow: MutableStateFlow<SkyWinUiState> =
        MutableStateFlow(DEFAULT_STATE)

    //export to ui layer
    val skyWinStateFlow: StateFlow<SkyWinUiState> = _mutableUiStateFlow.asStateFlow()


    private lateinit var originDataFlow: StateFlow<Any?>


    init {
        Log.i(TAG, "start: 激活数据层数据监听")
        /**
         * 在domainScope 监听数据层的原始数据
         * 将数据层的数据转为UI层使用的UiState数据
         *
         * */
        domainScope.launch { //将 domainScope 作为数据监听协程
            val originWinPosFlow = windowRepository.getSkyWindowPosFlow().filter { it is Int }.stateIn(domainScope)
            val originWinStateFlow = windowRepository.getSkyWindowStateFlow().filter { it is Int }.stateIn(domainScope)

            combine(originWinStateFlow,originWinPosFlow){ state,pos->
                Log.i(TAG, "combine: ${state} ${pos}")
                val curState = _mutableUiStateFlow.value
                when(state){
                    BCMRepositoryImpl.SKY_WIN_CLOSED->{//关闭
                        curState.copy(
                            windowState = state,
                            openEnable = true,
                            skyWindTextRes = R.string.sky_win_open_text,
                            posValue = 0,
                            posEnable = true
                        )
                    }
                    BCMRepositoryImpl.SKY_WIN_OPENING->{//正在打开
                       curState.copy(
                           windowState = state,
                            openEnable = true,
                            skyWindTextRes = R.string.sky_win_opening_text,
                            posEnable = true
                        )

                    }
                    BCMRepositoryImpl.SKY_WIN_STOP->{
                        curState.copy(
                            windowState = state,
                            openEnable = true,
                            skyWindTextRes = R.string.sky_win_close_text,
                            posValue = pos as Int,
                            posEnable = true
                        )
                    }
                    BCMRepositoryImpl.SKY_WIN_OPENED->{//完全打开
                        curState.copy(
                            windowState = state,
                            openEnable = true,
                            skyWindTextRes = R.string.sky_win_close_text,
                            posValue = 100,
                            posEnable = true
                        )
                    }
                    BCMRepositoryImpl.SKY_WIN_CLOSING ->{
                        curState.copy(
                            windowState = state,
                            openEnable = true,
                            skyWindTextRes = R.string.sky_win_closing_text,
                            posValue = 0,
                            posEnable = true
                        )
                    }
                    else->{
                        SkyWinUiState()
                    }
                }


            }.collect{uiState->
                _mutableUiStateFlow.update { uiState }
            }

           /* originDataFlow.transform<Any?, SkyWinUiState> { signalState ->
                Log.i(TAG, "transform: ${signalState}")
                val uiState = when (signalState) {
                    0 -> {//全关
                        SkyWinUiState(openEnable = true, skyWindTextRes = R.string.sky_win_close_text)
                    }

                    100 -> {//全开
                        SkyWinUiState(openEnable = true, skyWindTextRes = R.string.sky_win_open_text)
                    }

                    in 1..99 -> {//其他有效值
                        SkyWinUiState(openEnable = true, skyWindTextRes = R.string.sky_win_opening_text, posValue = signalState as Int, posEnable = false)
                    }

                    else -> {
                        SkyWinUiState(openEnable = false, posEnable = false)
                    }
                }
                Log.i(
                    TAG,
                    "transform 将数据层的原始数据转为Ui层的显示数据，并交给 网域层的flow向上流动数据"
                )
                _mutableUiStateFlow.emit(uiState)
            }.collect()//激活flow*/
        }
    }


    /**
     * 定义调用方法
     * 在domainScope 开启协程处理
     * */
    operator fun invoke(pos: Int) = domainScope.launch(Dispatchers.Default){
        //ui先行方案一 业务层进行处理 UI 先更改
        when (pos) {//close
            0 -> {
                _mutableUiStateFlow.update { cur ->
                    cur.copy(openEnable = false, windowState = BCMRepositoryImpl.SKY_WIN_CLOSING,  posValue = 0)
                }
            }
            100 -> {
                _mutableUiStateFlow.update { cur ->
                    cur.copy(openEnable = false, windowState =  BCMRepositoryImpl.SKY_WIN_OPENING,  posValue = 100)
                }
            }
            else-> {
                _mutableUiStateFlow.update { cur ->
                    cur.copy(openEnable = false, windowState =  BCMRepositoryImpl.SKY_WIN_OPENED, posValue = pos)
                }
            }
        }
        /**
         * 切换到IO线程执行 IPC 数据操作 ，并同步给出结果
         * 使用withContext 可以让整个流程串行执行 如果需要多个并行操作并要结果 需要使用async异步协程后调用await
         * */
        val result = withContext(Dispatchers.IO) {
            windowRepository.setSkyWindowPos(pos)
        }

        val asyncJob_1 = async { delay(100)
            1
        }
        val asyncJob_2 = async { delay(100)
            2
        }
        /**
         * 这里调用await方法，会等待 async代码块执行完成 给出结果
         * 这里的耗时是100
         * */
        val asyncResults = asyncJob_1.await()+asyncJob_2.await()

        /**
         * 获取执行结果后，切换回当前协程
         * */
        if (result.isSuccess) {//调用成功

        } else {

        }
    }

    fun skyWinClicked() {
        val windowState = skyWinStateFlow.value.windowState
        Log.i(TAG, "skyWinClicked: $windowState")
        when (windowState) {
            BCMRepositoryImpl.SKY_WIN_CLOSED->{//关闭状态下点击 执行开启
                Log.i(TAG, "skyWinClicked: closed to opening")
                invoke(100)
            }
            BCMRepositoryImpl.SKY_WIN_OPENING->{//正在打开
                Log.e(TAG, "skyWinClicked: opening" )
            }
            BCMRepositoryImpl.SKY_WIN_STOP->{//停止
                Log.i(TAG, "skyWinClicked: stop to closing")
                invoke(0)
            }
            BCMRepositoryImpl.SKY_WIN_CLOSING->{//正在关闭
                Log.e(TAG, "skyWinClicked: closing", )
                 }
            BCMRepositoryImpl.SKY_WIN_OPENED->{//打开
                Log.i(TAG, "skyWinClicked: opened to closing")
                invoke(0)
            }
            else -> {}
        }
    }


}
